function render() {
  console.log("模拟视图渲染");
}
let data = { name: "浪里行舟", location: { x: 100, y: 100 } };

methods.forEach((method) => {
  proto[method] = function () {
    // AOP
    arrayProto[method].call(this, ...arguments);
    render();
  };
});
function observe(obj) {
  if (Array.isArray(obj)) {
    obj.__proto__ = proto;
    return;
  }
  // 我们来用它使对象变成可观察的
  // 判断类型
  if (!obj || typeof obj !== "object") {
    return;
  }
  Object.keys(obj).forEach((key) => {
    defineReactive(obj, key, obj[key]);
  });

  function defineReactive(obj, key, value) {
    // 递归子属性
    observe(value);

    Object.defineProperty(obj, key, {
      enumerable: true, //可枚举（可以遍历）
      configurable: true, //可配置（比如可以删除）
      get: function reactiveGetter() {
        console.log("get", value); // 监听
        return value;
      },
      set: function reactiveSetter(newVal) {
        observe(newVal);
        //如果赋值是一个对象，也要递归子属性
        if (newVal !== value) {
          console.log("set", newVal); // 监听
          render();
          value = newVal;
        }
      },
    });
  }
}

data.location = { x: 1000, y: 1000 }; //set {x: 1000,y: 1000} 模拟视图渲染

data.name; // get 浪里行舟

/**
 * a. 无法检测到对象属性的添加和删除
 * b. 不能监听数组的变化，需要进行数组方法的重新
 */

let obj = [1, 2, 3];
let methods = ["pop", "shift", "unshift", "sort", "reverse", "splice", "push"];
// 先获取到原来的原型上的方法
let arrayProto = Array.prototype;
// 创建一个自己的原型 并且重写methods这些方法
let proto = Object.create(arrayProto);
methods.forEach((method) => {
  proto[method] = function () {
    // AOP
    arrayProto[method].call(this, ...arguments);
    render();
  };
});

function observer(obj) {
  // 把所有的属性定义成set/get的方式
  if (Array.isArray(obj)) {
    obj.__proto__ = proto;
    return;
  }
  if (typeof obj == "object") {
    for (let key in obj) {
      defineReactive(obj, key, obj[key]);
    }
  }
}
function defineReactive(data, key, value) {
  observer(value);
  Object.defineProperty(data, key, {
    get() {
      return value;
    },
    set(newValue) {
      observer(newValue);
      if (newValue !== value) {
        render();
        value = newValue;
      }
    },
  });
}
observer(obj);
function $set(data, key, value) {
  defineReactive(data, key, value);
}
obj.push(123, 55);
console.log(obj); //[1, 2, 3, 123, 55]
